<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script id="ColorVertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_PointSize;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = u_PointSize;
    }
</script>
<script id="ColorFragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    void main(){
        if(distance(gl_PointCoord,vec2(0.5, 0.5)) < 0.5){
            gl_FragColor = u_Color;
        }
    }
</script>
<script type="module">
    import { Matrix4, Vector3, Color, OrthographicCamera, PerspectiveCamera, Spherical } from '../js/three.module.js';
    import { CreateProgram, imgPromise } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    import CameraController from '../js/CameraController.js'
    import Poly from '../js/Poly4.js'

    import Geo from '../js/Poly2/Geo.js'
    import Mat from '../js/Poly2/Mat.js'
    import Obj3D from '../js/Poly2/Obj3D.js'
    import Scene from '../js/Poly2/Scene.js'



    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl", { antialias: true, });

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);//去图片描边
    gl.enable(gl.DEPTH_TEST);
    //#endregion



    const scene = new Scene({ gl: gl });
    scene.addAxisProgram();
    scene.regProgram('color', {
        program: CreateProgram(gl,
            document.querySelector('#ColorVertexShader').innerText,
            document.querySelector('#ColorFragmentShader').innerText),
        attribs: ['a_Position'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_PointSize', 'u_Color']
    })


    const pvM4 = new Matrix4();
    const modelM4 = new Matrix4()
        .setPosition(0, 0, 0)
        .multiply(new Matrix4().makeRotationY(0 * Math.PI / 180));
    const E = new Vector3(2.655879365237089, 2.3338263102096892, -2.511883665913061);
    const L = new Vector3(0, 0, 0);

    const camera = new PerspectiveCamera(45, canvas.width / canvas.height, 1, 20);
    const cameraController = new CameraController({
        canvas,
        camera,
        pvMatrix: pvM4,
        eye: E,
        lookAt: L,
    });

    const nodeLength = 0.5;
    const nodeArr = [
        -nodeLength, 0.2, -nodeLength,
        -nodeLength, 0, nodeLength,
        nodeLength, 0, nodeLength,
        nodeLength, 0, -nodeLength,
    ];
    const elementArr = [
        0, 1, 2,
        0, 2, 3,
    ];


    //平面
    let face = createFace(nodeArr)
    scene.add(face);
    //坐标轴
    let axis = new Obj3D().createAxis('axis');
    scene.add(axis);

    createTestLines(face);

    canvas.addEventListener('mousemove', function () {


        //视线方向
        let V = L.clone().sub(E);
        //投到平面上的方向
        let VF = new Vector3(V.x, 0, V.z);

    })

    window.addEventListener('keyup', function (e) {
        if (e.keyCode == 32) {
            createTestLines(face);
        }
    });


    function getOrginOfEyeInvert(E, C, array) {
        //方向, 
        const V = C.clone().sub(E).normalize();
        const Vnode = V.clone().add(C);
        Vnode.y = C.y;

        //获取方向最近的两个点
        let [near0, near1] = getNearNode(Vnode, array, 2);
        let [x, y] = [0, 0];

        scene.add(createLine(near0, near1, [Math.random(), Math.random(), Math.random(), 1]));

        if (V.x == 0) {
            x = 0;
            y = near0.z - C.z;
        } else if (V.z == 0) {
            x = near0.x - C.x;
            y = 0;
        } else if (Math.abs(V.x) < Math.abs(V.z)) {
            //获取视线的三角形
            let [d, l] = [V.x, V.z];
            //获取角度
            let J = d / l;
            y = near0.z - C.z;
            x = y * J;

        } else {
            let [d, l] = [V.z, V.x];
            //获取角度tan(J)
            let J = d / l;
            if (l == 0) {
                J = 0;
            }
            // J -= 45 * Math.PI / 180;
            x = near0.x - C.x;
            y = x * J;
        }


        let orgin = new Vector3(x, 0, y).add(C);
        orgin = lineIntersect(C, orgin, near0, near1);//这一步就已经求出了边上的位置
        //下面是为了弥补小范围高度差

        //开始算y
        //lb斜边长
        let lb = near0.clone().distanceTo(new Vector3(near1.x, near0.y, near1.z));
        orgin.y = near0.y;
        //所求的边长
        let lb2 = orgin.clone().distanceTo(near0);
        //方向
        let nfx = near1.clone().sub(near0).normalize();
        //方向 * 距离
        let o2 = nfx.clone().multiplyScalar(lb2 / lb).add(near0)


        return o2;
    }
    //获取图形中心点
    function getCenter(array) {
        let a = new Vector3(array[0], array[1], array[2]);
        let b = new Vector3(array[3 * 2], array[3 * 2 + 1], array[3 * 2 + 2]);
        return b.clone().sub(a).multiplyScalar(0.5).add(a);
    }
    //获取最近的几个点
    function getNearNode(node, array, count = 1) {
        let cds = [];
        for (let i = 0; i < array.length; i += 3) {
            let cur = new Vector3(array[i], array[i + 1], array[i + 2]);
            cds.push({ value: cur.distanceTo(node), index: i })
        }
        let rIndex = [];
        for (let i = 0; i < count; i++) {
            let min = cds[0];
            for (let j = 1; j < cds.length; j++) {
                if (min.value > cds[j].value) {
                    min = cds[j];
                }
            }

            rIndex.push(new Vector3(array[min.index], array[min.index + 1], array[min.index + 2]));
            cds.splice(min.index / 3, 1);
        }
        return rIndex;
    }
    function lineIntersect(p0, p1, p2, p3) {
        var A1 = p1.z - p0.z,
            B1 = p0.x - p1.x,
            C1 = A1 * p0.x + B1 * p0.z,
            A2 = p3.z - p2.z,
            B2 = p2.x - p3.x,
            C2 = A2 * p2.x + B2 * p2.z,
            denominator = A1 * B2 - A2 * B1;

        return new Vector3((B2 * C1 - B1 * C2) / denominator, 0, (A1 * C2 - A2 * C1) / denominator);
    }


    function createTestLines(obj) {
        let color = [Math.random(), Math.random(), Math.random(), 1];
        //先变换
        obj.allTransform();
        let array = obj.geo.data['a_Position'].array;
        //获取平面中心点
        let C = getCenter(array)
        //视线
        let EC_Line = createLine(E, C, color);
        scene.add(EC_Line);
        //视线方向
        let V = C.clone().sub(E).normalize();
        let V_Line = createLine(C, V.clone().add(C), color)
        scene.add(V_Line);
        //投到平面上的方向(这个地方开始)
        let VF = new Vector3(V.clone().add(C).x, 0, V.clone().add(C).z);//这个地方
        let VF_Line = createLine(C, VF, color)
        scene.add(VF_Line);
        //根据中心点再次创建方向轴



        let O = getOrginOfEyeInvert(E, C, array);


        let CO_Line = createLine(C, O, [1, 0, 0.5, 1])
        scene.add(CO_Line);
    }


    function createNode(a, color = [0, 1, 0, 1]) {
        return new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 3, array: new Float32Array([a.x, a.y, a.z]) },
                },
            }),
            mat: new Mat({
                program: 'color',
                mode: ['LINES', 'POINTS'],
                data: {
                    'u_PvM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                    'u_ModelM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                    'u_PointSize': { type: 'uniform1f', value: 10 },
                    'u_Color': { type: 'uniform4fv', value: color },
                },
            }),
        });
    }

    function createFace(array, color = [1, 1, 1, 1]) {
        return new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 3, array: new Float32Array(nodeArr) },
                },
                element: {
                    array: new Uint16Array(elementArr)
                }
            }),
            mat: new Mat({
                program: 'color',
                mode: ['TRIANGLES'],
                data: {
                    'u_PvM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                    'u_ModelM4': { type: 'uniformMatrix4fv', value: modelM4.elements },
                    'u_PointSize': { type: 'uniform1f', value: 30 },
                    'u_Color': { type: 'uniform4fv', value: [1, 1, 1, 1] },
                },
            }),
        });
    }

    function createLine(a, b, color = [1, 0, 0, 1]) {
        return new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 3, array: new Float32Array([a.x, a.y, a.z, b.x, b.y, b.z]) },
                },
                element: { array: new Uint16Array([0, 1]) }
            }),
            mat: new Mat({
                program: 'color',
                mode: ['LINES', 'POINTS'],
                data: {
                    'u_PvM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                    'u_ModelM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                    'u_PointSize': { type: 'uniform1f', value: 10 },
                    'u_Color': { type: 'uniform4fv', value: color },
                },
            }),
        });
    }

    function draw() {

        scene.setUniform('u_PvM4', { value: pvM4.elements })
        scene.draw();
    }

    (function ani() {
        draw();
        requestAnimationFrame(ani);
    }
    )();

</script>

</html>